package com.ocp.socket.server.mina;

import com.example.app.api.userinfo.bean.User;
import com.ocp.socket.busi.device.bean.DeviceInfo;
import com.ocp.socket.busi.device.bean.LineInfo;
import com.ocp.socket.busi.device.service.IDeviceInfoService;
import com.ocp.socket.busi.userinfo.service.IUserInfoService;
import com.ocp.socket.busi.warnMsg.service.IWarnMsgService;
import com.ocp.socket.common.Constants;
import com.ocp.socket.common.bean.DevInfo;
import com.ocp.socket.common.bean.UserInfo;
import com.ocp.socket.common.enums.MsgTypeEnum;
import com.ocp.socket.common.utils.DateUtil;
import com.ocp.socket.common.utils.EnumUtil;
import com.ocp.socket.common.utils.SessionUtil;
import com.ocp.socket.server.vo.DataVo;
import com.ocp.socket.server.vo.MessageVo;
import org.apache.commons.lang3.StringUtils;
import org.apache.mina.core.filterchain.IoFilterAdapter;
import org.apache.mina.core.session.IoSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @Author : lichong
 * @description :
 * @Date Create in 13:18 2019/3/9
 * @Modified By : 自定义身份认证拦截器  验证连接的合法性和 温度气压数据值得修正
 **/
public class ConnectAuthFilter extends IoFilterAdapter {

    private final Logger logger = LoggerFactory.getLogger(ConnectAuthFilter.class);

    private IUserInfoService userInfoService;
    private IDeviceInfoService deviceInfoService;
    @Autowired
    private IWarnMsgService warnMsgService;

    public ConnectAuthFilter(IUserInfoService userInfoService, IDeviceInfoService deviceInfoService) {
        this.userInfoService = userInfoService;
        this.deviceInfoService = deviceInfoService;
    }

    @Override
    public void messageReceived(NextFilter nextFilter, IoSession session, Object message) throws Exception {
        MessageVo messageVo = (MessageVo) message;
        if (Constants.RETURN_CODE_SUCCESS.equals(messageVo.getReturnCode())) {
            String appType = EnumUtil.getMstAppType(messageVo.getModel());
            String snNo = messageVo.getSn();
            logger.info("snNo:============" + snNo);
            //如果是时间获取报文
            if (MsgTypeEnum.NORM.getTypeCode().equals(messageVo.getModel())) {
                //返回信息拼接
                StringBuffer returnVal = new StringBuffer();
                returnVal.append(messageVo.getModel());
                returnVal.append(DateUtil.getNowStr(DateUtil.PATTERN_12));
                returnVal.append("TIME");
                session.write(returnVal.toString());
            } else if (Constants.DEVICE_TYPE_DEVICE.equals(appType)) { //如果是设备
                //获取设备信息
                DeviceInfo deviceInfo = deviceInfoService.getDeviceInfo(snNo);
                if (deviceInfo != null) {
                    DevInfo devInfo = new DevInfo();
                    BeanUtils.copyProperties(deviceInfo, devInfo);
                    //检查是否是最新的数据
                    if (deviceInfoService.checkNewData(messageVo)) {
                        /*
                            验证数据正确则处理下面逻辑
                         */
                        //第一连接判断该设备是否有断线的预警信息
                        if (session.getAttribute(Constants.ATTRIBUTE_KEY_AUTH) == null) {
                            //放入session值
                            session.setAttribute(Constants.ATTRIBUTE_KEY_AUTH, devInfo);
                            //添加在线队列
                            SessionUtil.addDeviceSessionMap(deviceInfo.getSnNo(), session);
                        }
                        //放入在线队列值
                        deviceInfoService.addDevInfoIntoSet(devInfo);
                        //检查是否是否到正常的连接，并清除报警信息，正常数量+1
                        checkNormalConnectAndCleanMsg(session, devInfo, messageVo);
                        //删除不用的数据和修正数据
                        checkAndCorrect(messageVo, deviceInfo);
                    }
                } else {
                    messageVo.setReturnCode(Constants.RETURN_CODE_FAIL);
                    messageVo.setReturnMsg("不合法的snNo");
                }
            } else if (Constants.DEVICE_TYPE_APP.equals(appType)) {
                //如果是app获取用户登录信息
                User user = userInfoService.getUserInfo(snNo, session.getId());
                if (user != null) {
                    //判断用户是不是第一次传标识信息
                    if (session.getAttribute(Constants.ATTRIBUTE_KEY_AUTH) == null) {
                        UserInfo userInfo = new UserInfo();
                        BeanUtils.copyProperties(user, userInfo);
                        session.setAttribute(Constants.ATTRIBUTE_KEY_AUTH, userInfo);
                        //如果是第一次传标识信息，则判断用户是否是在连接中,如果存在给他发送在别处登录的消息，并且断掉连接
                        SessionUtil.checkAppSnNoConnected(user.getOrgId(), user.getOpenId());
                        //添加在线队列
                        SessionUtil.addAppSessionMap(user.getOrgId(), session);
                        logger.info("用户登录成功================{}", snNo);
                    }
                } else {
                    messageVo.setReturnCode(Constants.RETURN_CODE_FAIL);
                    messageVo.setReturnMsg("不合法的snNo");
                    logger.error("用户登录失败------------------{}", snNo);
                }
            }
        }
        //如果数据错误直接断了连接
        if(!Constants.RETURN_CODE_SUCCESS.equals(messageVo.getReturnCode())) {
            returnErrorMsg(messageVo, session);
        } else {
            super.messageReceived(nextFilter, session, message);
        }
    }

    /**
     * 返回错误的信息，断开连接
     * @param messageVo
     * @param session
     */
    public void returnErrorMsg(MessageVo messageVo, IoSession session) {
        //返回信息拼接
        StringBuffer returnVal = new StringBuffer();
        if(messageVo != null && messageVo.getDataHeader()!=null){
            returnVal.append(messageVo.getDataHeader());
        }
        if(messageVo != null && messageVo.getReturnCode()!=null){
            returnVal.append(messageVo.getReturnCode());
        }
        if(messageVo != null && messageVo.getReturnMsg()!=null){
            returnVal.append(messageVo.getReturnMsg());
        }
        session.write(returnVal.toString());
        session.closeNow();
    }

    /**
     * 删除未配置的线路和修正温度和气压值
     * @param message       接收的消息信息
     * @param deviceInfo    查询的设备信息
     */
    private void checkAndCorrect(MessageVo message, DeviceInfo deviceInfo) {
        Map<String, DataVo> dataMap = new HashMap<>(16);
        List<LineInfo> lineInfos = deviceInfo.getLineInfos();
        if (CollectionUtils.isEmpty(lineInfos)) {
            message.setDataVoMap(dataMap);
        }
        //获取配置的线路信息
        Map<String, LineInfo> lineInfoMap = lineInfos.stream().collect(Collectors.
                toMap(LineInfo::getLineCode, Function.identity(), (key1, key2) -> key1));
        Map<String, DataVo> dataVoMap = message.getDataVoMap();
        Iterator<Map.Entry<String, DataVo>> iterator = dataVoMap.entrySet().iterator();
        String lineCode = null;
        DataVo data = null;
        BigDecimal deviationVal, value;
        while (iterator.hasNext()) {
            Map.Entry<String, DataVo> next = iterator.next();
            lineCode = next.getKey();
            data = next.getValue();
            try{
                new BigDecimal(StringUtils.remove(data.getVal()," "));
            }catch(NumberFormatException e){
                logger.error("信息中出现非数字数据！message:{},data:{}", message, data);
                continue;
            }
            LineInfo lineInfo = lineInfoMap.get(lineCode);
            //如果配置的线路信息不为空获取该信息
            if (lineInfo != null) {
                //如果是压力或温度值修改值
                if (message.getModel().equals(MsgTypeEnum.AIRP.getTypeCode())
                        || message.getModel().equals(MsgTypeEnum.TEMP.getTypeCode())) {
                    deviationVal = lineInfo.getDeviationVal() == null ? BigDecimal.ZERO : lineInfo.getDeviationVal();
                    if (StringUtils.isNotBlank(data.getVal())) {
                        value = new BigDecimal(StringUtils.remove(data.getVal()," "));
                        /*if (message.getModel().equals(MsgTypeEnum.AIRP.getTypeCode()) && lineCode.equals("L01")) {
                            value = Constants.BASE_AIRP.divide(value);
                        }*/
                        value = value.add(deviationVal);
                        data.setVal(value.toString());
                    }
                }
                dataMap.put(lineCode, data);
            }
        }
        message.setDataVoMap(dataMap);
    }

    /**
     * 检查是否到正常的连接，并清除报警
     * @param session
     */
    private void checkNormalConnectAndCleanMsg(IoSession session, DevInfo devInfo, MessageVo messageVo) {
        if (!messageVo.isNewDataFlag()) {
            return;
        }
        //获取有效的心跳数量
        Integer connectNum = (Integer)session.getAttribute(Constants.ATTRIBUTE_KEY_VALID_CONNECT_NUM);
        if (connectNum == null) {
            connectNum = 0;
        }
        connectNum = connectNum + 1;
        logger.debug("==================snNo:{},normal connect num :{} ===============",devInfo.getSnNo(), connectNum);
        //更新有效的心跳连接
        session.setAttribute(Constants.ATTRIBUTE_KEY_VALID_CONNECT_NUM, connectNum);
        //删除报警信息
        if (connectNum == Constants.NORMAL_CONNECT_NUM) {
            warnMsgService.updateWarnMsgFinishTime(devInfo.getSnNo());
        }
    }
}
